﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Drawing;
using System.Windows.Forms;
using DevAge.ComponentModel.Converter;
using DevAge.ComponentModel.Validator;
using DevAge.Drawing;
using SourceGrid;
using SourceGrid.Cells;
using SourceGrid.Cells.Controllers;
using SourceGrid.Cells.Editors;
using ZeBobo5.LibraryHelper.Core.Grid.Controllers;
using CheckBox=SourceGrid.Cells.CheckBox;
using ColumnHeader=SourceGrid.Cells.ColumnHeader;
using ComboBox=SourceGrid.Cells.Editors.ComboBox;
using ContentAlignment=DevAge.Drawing.ContentAlignment;
using Image=System.Drawing.Image;
using TextBox=SourceGrid.Cells.Editors.TextBox;

namespace ZeBobo5.LibraryHelper.Core.Grid
{
    public class GridHelper
    {
        #region AddController

        public static ICell AddController(ICell cell, IController controller)
        {
            cell.AddController(controller);
            return cell;
        }

        public static void AddController(SourceGrid.Grid.GridRow row, IController controller)
        {
            for (int cpt = 0; cpt < row.Grid.Columns.Count; cpt++)
            {
                if (row.Grid.GetCell(row.Index, cpt) != null)
                {
                    AddController((ICell) row.Grid.GetCell(row.Index, cpt), controller);
                }
            }
        }

        #endregion

        #region RemoveController

        public static ICell RemoveController<T>(ICell cell) where T : IController
        {
            IController controllerToRemove = cell.Controller.FindController(typeof (T));
            if (controllerToRemove != null)
            {
                cell.RemoveController(controllerToRemove);
            }
            return cell;
        }

        public static void RemoveController<T>(SourceGrid.Grid.GridRow row) where T : IController
        {
            for (int cpt = 0; cpt < row.Grid.Columns.Count; cpt++)
            {
                if (row.Grid.GetCell(row.Index, cpt) != null)
                {
                    RemoveController<T>((ICell) row.Grid.GetCell(row.Index, cpt));
                }
            }
        }

        #endregion

        #region ClearGrid

        public static void ClearGrid(GridBase grid)
        {
            grid.Rows.Clear();
        }

        public static void ClearGrid(GridBase grid, int startingClearingRowIndex)
        {
            if (grid.Rows.Count > startingClearingRowIndex)
            {
                grid.Rows.RemoveRange(startingClearingRowIndex, grid.Rows.Count - startingClearingRowIndex);
            }
        }

        #endregion

        #region GetCellBackColor

        public static ICell SetCellBackColor(RowHeader cell, Color color)
        {
            DevAge.Drawing.VisualElements.RowHeader header = new DevAge.Drawing.VisualElements.RowHeader();
            header.BackgroundColorStyle = BackgroundColorStyle.Solid;
            header.BackColor = color;

            ((SourceGrid.Cells.Views.RowHeader) cell.View).Background = header;
            return cell;
        }

        public static ICell SetCellBackColor(ColumnHeader cell, Color color)
        {
            DevAge.Drawing.VisualElements.ColumnHeader header = new DevAge.Drawing.VisualElements.ColumnHeader();
            header.BackgroundColorStyle = BackgroundColorStyle.Solid;
            header.BackColor = color;

            ((SourceGrid.Cells.Views.ColumnHeader) cell.View).Background = header;
            return cell;
        }

        public static ICell SetCellBackColor(ICell cell, Color color)
        {
            cell.View.BackColor = color;
            return cell;
        }

        #endregion

        public static RectangleBorder GetCellBorder(ICell cell)
        {
            return (RectangleBorder) cell.View.Border;
        }

        public static ICell GetCheckBoxCell()
        {
            ICell cell = new CheckBox();
            cell.View = new SourceGrid.Cells.Views.CheckBox();
            cell.Editor = new EditorBase(typeof (bool));
            return cell;
        }

        public static ColumnHeader GetColumnHeader(string value)
        {
            ColumnHeader head = new ColumnHeader(value);
            head.View = new SourceGrid.Cells.Views.ColumnHeader();
            SetAlignment(head, ContentAlignment.MiddleLeft);
            return head;
        }

        public static RowHeader GetRowHeader(string value)
        {
            RowHeader head = new RowHeader(value);
            head.View = new SourceGrid.Cells.Views.RowHeader();
            SetAlignment(head, ContentAlignment.MiddleLeft);
            return head;
        }

        public static bool IsEnable(ICell cell)
        {
            if (cell.Editor != null)
            {
                if (cell.Editor.EditableMode == EditableMode.None)
                {
                    return false;
                }
                return true;
            }
            throw new Exception("No editor assign to cell.");
        }

        public static ICell SetAlignment(ICell cell, ContentAlignment alignment)
        {
            cell.View.TextAlignment = alignment;
            return cell;
        }

        public static ICell SetCellBorder(ICell cell, RectangleBorder border)
        {
            cell.View.Border = border;
            return cell;
        }

        public static ICell SetEnable(ICell cell, bool enable)
        {
            if (cell.Editor != null)
            {
                cell.Editor.EditableMode = enable ? EditableMode.Default : EditableMode.None;
            }
            else
            {
                throw new Exception("Cette cellule n'a pas d'éditor.");
            }
            return cell;
        }

        public static ICell SetImage(ICell cell, Image image)
        {
            cell.Image = image;
            return cell;
        }

        #region SetColumnSortable

        public static void SetColumnSortable(GridBase grid)
        {
            SetColumnSortable(grid, 0);
        }

        public static void SetColumnSortable(GridBase grid, int rowHeaderIndex)
        {
            SetColumnSortable(grid, rowHeaderIndex, rowHeaderIndex + 1);
        }

        public static void SetColumnSortable(GridBase grid, int rowHeaderIndexStart, int rowHeaderIndexEnd)
        {
            SetColumnSortable(grid, rowHeaderIndexStart, rowHeaderIndexEnd, rowHeaderIndexEnd + 1);
        }

        public static void SetColumnSortable(GridBase grid, int rowHeaderIndex, int rowHeaderIndexEnd,
                                             int startingRowIndex)
        {
            SetColumnSortable(grid, rowHeaderIndex, rowHeaderIndexEnd, startingRowIndex, startingRowIndex);
        }

        public static void SetColumnSortable(GridBase grid, int rowHeaderIndex, int rowHeaderIndexEnd,
                                             int startingRowIndex, int endingRowIndex)
        {
            if (rowHeaderIndex > rowHeaderIndexEnd)
            {
                return;
            }
            if (grid.Rows.Count < rowHeaderIndex)
            {
                throw new Exception("La grille n'a pas de rowIndexHeader");
            }

            for (int indexrow = rowHeaderIndex; indexrow <= rowHeaderIndexEnd; indexrow++)
            {
                for (int index = 0; index <= grid.Columns.Count - 1; index++)
                {
                    if (grid[indexrow, index] is ColumnHeader)
                    {
                        SetColumnSortable(grid, (ColumnHeader) grid[indexrow, index], startingRowIndex, endingRowIndex);
                    }
                }
            }
        }

        public static void SetColumnSortable(GridBase grid, ColumnHeader header, int rowHeaderIndexEnd)
        {
            SetColumnSortable(grid, header, rowHeaderIndexEnd, header.Row.Index + 1);
        }

        public static void SetColumnSortable(GridBase grid, ColumnHeader header, int rowHeaderIndexEnd,
                                             int startingRowIndex)
        {
            SetColumnSortable(grid, header, rowHeaderIndexEnd, startingRowIndex, grid.Rows.Count - 1);
        }

        public static void SetColumnSortable(GridBase grid, ColumnHeader header, int rowHeaderIndexEnd,
                                             int startingRowIndex, int endingRowIndex)
        {
            IController ctrl =
                grid[header.Row.Index, header.Column.Index].Controller.FindController(typeof (SortableHeader));
            if (ctrl != null)
            {
                grid[header.Row.Index, header.Column.Index].Controller.RemoveController(ctrl);
            }
            ctrl =
                grid[header.Row.Index, header.Column.Index].Controller.FindController(typeof (SortableHeaderController));
            if (ctrl != null)
            {
                grid[header.Row.Index, header.Column.Index].Controller.RemoveController(ctrl);
            }

            if (startingRowIndex > endingRowIndex)
            {
                return;
            }

            RangeLoader rangeHeader = new RangeLoader(new Range(0, 0, rowHeaderIndexEnd, grid.Columns.Count - 1));
            RangeLoader rangeToSort =
                new RangeLoader(new Range(startingRowIndex, 0, endingRowIndex, grid.Columns.Count - 1));
            SortableHeaderController sortableController = new SortableHeaderController(rangeToSort, rangeHeader);
            grid[header.Row.Index, header.Column.Index].AddController(sortableController);
            ((ColumnHeader) grid[header.Row.Index, header.Column.Index]).AutomaticSortEnabled = false;
        }

        #endregion

        #region GetTextCell

        public static ICell GetTextCell()
        {
            return GetTextCell("");
        }

        public static ICell GetTextCell(ContentAlignment alignment)
        {
            return SetAlignment(GetTextCell(), alignment);
        }

        public static ICell GetTextCell(ContentAlignment alignment, Color backColor)
        {
            return SetCellBackColor(GetTextCell(alignment), backColor);
        }

        public static ICell GetTextCell(ContentAlignment alignment, bool enable)
        {
            return SetEnable(GetTextCell(alignment), enable);
        }

        public static ICell GetTextCell(ContentAlignment alignment, Color backColor, bool enable)
        {
            return SetEnable(GetTextCell(alignment, backColor), enable);
        }

        public static ICell GetTextCell(Color backColor)
        {
            return SetCellBackColor(GetTextCell(), backColor);
        }

        public static ICell GetTextCell(Color backColor, bool enable)
        {
            return SetCellBackColor(SetEnable(GetTextCell(), enable), backColor);
        }

        public static ICell GetTextCell(bool enable)
        {
            return SetEnable(GetTextCell(), enable);
        }

        public static ICell GetTextCell(object value)
        {
            ICell cell = new Cell(value, new TextBox(typeof (string)));
            cell.View = new SourceGrid.Cells.Views.Cell();
            return SetAlignment(cell, ContentAlignment.MiddleLeft);
        }

        public static ICell GetTextCell(object value, ContentAlignment alignment)
        {
            return SetAlignment(GetTextCell(value), alignment);
        }

        public static ICell GetTextCell(object value, ContentAlignment alignment, Color backColor)
        {
            return SetCellBackColor(GetTextCell(value, alignment), backColor);
        }

        public static ICell GetTextCell(object value, ContentAlignment alignment, Color backColor, bool enable)
        {
            return SetEnable(GetTextCell(value, alignment, backColor), enable);
        }

        public static ICell GetTextCell(object value, ContentAlignment alignment, bool enable)
        {
            return SetEnable(GetTextCell(value, alignment), enable);
        }

        public static ICell GetTextCell(object value, Color backColor)
        {
            return SetCellBackColor(GetTextCell(value), backColor);
        }

        public static ICell GetTextCell(object value, Color backColor, bool enable)
        {
            return SetEnable(GetTextCell(value), enable);
        }

        public static ICell GetTextCell(object value, bool enable)
        {
            return SetEnable(GetTextCell(value), enable);
        }

        #endregion

        #region GetComboCell

        public static ICell GetComboCell<TValue>(IList<TValue> lstValues)
        {
            ICell cell = new Cell();
            cell.View = new SourceGrid.Cells.Views.Cell();
            ComboBox editor = new ComboBox(typeof (TValue), (ICollection) lstValues, true);
            editor.Control.AutoCompleteSource = AutoCompleteSource.ListItems;
            editor.Control.AutoCompleteMode = AutoCompleteMode.SuggestAppend;
            cell.Editor = editor;
            return cell;
        }

        public static ICell GetComboCell<TValue>(IList<TValue> lstValues, TValue value)
        {
            ICell cell = GetComboCell(lstValues);
            cell.Value = value;
            return cell;
        }

        public static ICell GetComboCell<TKey, TValue>(IDictionary<TKey, TValue> lstValues)
        {
            return GetComboCell(lstValues.Keys, lstValues.Values);
        }

        public static ICell GetComboCell<TKey, TValue>(IDictionary<TKey, TValue> lstValues, TKey values)
        {
            ICell cell = GetComboCell(lstValues);
            cell.Value = values;
            return cell;
        }

        public static ICell GetComboCell<TKey, TValue>(ICollection<TKey> lstKeys, ICollection<TValue> lstValues)
        {
            return GetComboCell(new List<TKey>(lstKeys), new List<TValue>(lstValues));
        }

        public static ICell GetComboCell<TKey, TValue>(ICollection<TKey> lstKeys, ICollection<TValue> lstValues,
                                                       TKey value)
        {
            ICell cell = GetComboCell(lstKeys, lstValues);
            cell.Value = value;
            return cell;
        }

        public static ICell GetComboCell<TKey, TValue>(IList<TKey> lstKeys, IList<TValue> lstValues)
        {
            ComboBox editor = new ComboBox(typeof (TKey), (ICollection) lstKeys, true);
            editor.Control.FormattingEnabled = true;
            editor.Control.AutoCompleteSource = AutoCompleteSource.ListItems;
            editor.Control.AutoCompleteMode = AutoCompleteMode.SuggestAppend;

            ValueMapping vm = new ValueMapping();
            vm.DisplayStringList = (IList) lstValues;
            vm.ValueList = (IList) lstKeys;
            vm.SpecialList = (IList) lstValues;
            vm.SpecialType = typeof (TValue);
            vm.BindValidator(editor);

            ICell cell = new Cell();
            cell.View = new SourceGrid.Cells.Views.Cell();
            cell.Editor = editor;
            return cell;
        }

        public static ICell GetComboCell<TKey, TValue>(IList<TKey> lstKeys, IList<TValue> lstValues, TValue value)
        {
            ICell cell = GetComboCell(lstKeys, lstValues);
            cell.Value = value;
            return cell;
        }

        #endregion

        #region GetNumericCell

        public static ICell GetNumericCell<T>()
        {
            object value = 0;
            return GetNumericCell((T) value);
        }

        public static ICell GetNumericCell<T>(T value)
        {
            return GetNumericCell(value, "N0");
        }

        public static ICell GetNumericCell<T>(T value, string format)
        {
            ICell cell = new Cell(value, typeof (T));
            cell.View = new SourceGrid.Cells.Views.Cell();
            cell.Editor.TypeConverter = new NumberTypeConverter(typeof (T), format);
            return SetAlignment(cell, ContentAlignment.MiddleRight);
        }

        #endregion

        #region GetPercentageCell

        public static ICell GetPercentageCell<T>()
        {
            object value = 0;
            return GetPercentageCell((T) value);
        }

        public static ICell GetPercentageCell<T>(T value)
        {
            TextBox editorCustom = new TextBox(typeof (T));
            editorCustom.TypeConverter = new PercentTypeConverter(typeof (T));
            Cell cell = new Cell(value, editorCustom);
            cell.View = new SourceGrid.Cells.Views.Cell();
            return SetAlignment(cell, ContentAlignment.MiddleRight);
        }

        #endregion
    }
}